#!/usr/bin/python
# -*- coding: UTF-8 -*-

# CPU 和 内存监控

import rospy
import os,re
import subprocess
import time,datetime


class SystemMonitor:
    def __init__(self):
        rospy.init_node("system_monitor_node")
        self.__save_dir = "/home/aoting/user_config/logs/system/"
        if not os.path.exists(self.__save_dir):
            os.makedirs(self.__save_dir)
        uptime = self.getStartTime()
        uptime = uptime.replace(" ", "_").replace(":", "").replace("-", "")
        self.__log_file = os.path.join(self.__save_dir, "system_{}".format(uptime))
        self.__log_origin_file = self.__log_file
        self.__log_file = "{}.log".format(self.__log_file)
        self.__log_file_idx = 0
        print("log_file: {}".format(self.__log_file))
        if not os.path.exists(self.__log_file):
            with open(self.__log_file, 'w') as file:
                pass
        self.Loop()

    def getCmdWrite(self,cmd):
        '''获取指令输出'''
        result = os.popen(cmd)
        return result.read()

    def getSystemInfo(self):
        '''获取系统信息'''
        res = self.getCmdWrite("cat /etc/issue")
        res = res.split(" \\")[0]
        if res: return res
        else: return ""

    def getCPUInfo(self):
        '''获取CPU信息'''
        cpu_info = dict()
        res = self.getCmdWrite("cat /proc/cpuinfo | grep 'model name' | uniq")
        res = res.splitlines()
        if res: 
            cpu_info["model_name"] = res[0].split(": ")[1]

        res = self.getCmdWrite("cat /proc/cpuinfo | grep 'processor' | wc -l")
        res = res.splitlines()
        if res:
            cpu_info["processor"] = res[0]
        # print(res)
        return cpu_info


    def getDiskInfo(self):
        '''获取磁盘信息'''
        res = self.getCmdWrite("df -H")
        disk_info = {
            "name" : "",
            "Total" : "",
            "Used" : "",
            "Avail" : "",
            "Prec" : "",
        }
        disk_data = []
        for line in res.splitlines(): 
            line_split = line.split(" ")
            if line_split and line_split[-1] == "/":
                for item in line_split:
                    if item:
                        disk_data.append(item)
                break
        # print(disk_data, len(disk_data))
        if(len(disk_data) == 6):
            disk_info["name"] = disk_data[0]
            disk_info["Total"] = disk_data[1]
            disk_info["Used"] = disk_data[2]
            disk_info["Avail"] = disk_data[3]
            disk_info["Prec"] = disk_data[4]
        return disk_info


    def getStartTime(self):
        '''获取系统开机时间'''
        res = self.getCmdWrite("uptime -s")
        return res.split("\n")[0]

    def getLoadAverage(self):
        '''获取平均负载'''
        load_average = {
            "min_1": 0.0,
            "min_5": 0.0,
            "min_15": 0.0
        }
        res = self.getCmdWrite("uptime")
        for line in res.splitlines(): 
            line_split = line.split("load average: ")
            if line_split:
                info = line_split[-1].split(", ")
                # print(info, len(info))
                if(len(info) == 3):
                    load_average["min_1"] = info[0]
                    load_average["min_5"] = info[1]
                    load_average["min_15"] = info[2]
        return load_average

    def getTopInfo(self):
        result = subprocess.Popen(['top', '-bn1'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        stdout, stderr = result.communicate()
        output = stdout.decode('utf-8')  # Decode bytes to string
        lines = output.splitlines()
        top_five_lines = lines[:5]
        # print(top_five_lines)
        return top_five_lines
    
    # def GetCpuUsage(self, top_five_lines):
    #     cpu_usage_info = dict()
    #     if len(top_five_lines) != 5: return cpu_usage_info
    #     cpu_match = re.search(r'%Cpu\(s\):\s+(\d+\.\d+)\s+us,\s+(\d+\.\d+)\s+sy,\s+(\d+\.\d+)\s+ni,\s+(\d+\.\d+)\s+id,\s+(\d+\.\d+)\s+wa,\s+(\d+\.\d+)\s+hi,\s+(\d+\.\d+)\s+si,\s+(\d+\.\d+)\s+st', top_five_lines[2]) 
    #     if cpu_match:
    #         user = float(cpu_match.group(1))
    #         system = float(cpu_match.group(2))
    #         # 计算 CPU 总占用率（用户态 + 系统态）
    #         cpu_usage = user + system
    #         cpu_idle = float(cpu_match.group(4))
    #         # print("cpu_usage: {:.2f}%, cpu_idle: {:.2f}%".format(cpu_usage, cpu_idle))
    #         cpu_usage_info["cpu_usage"] = cpu_usage
    #         cpu_usage_info["cpu_idle"] = cpu_idle
    #     return cpu_usage_info

    def GetCpuUsage(self, top_five_lines):
        cpu_usage_info = dict()
        if len(top_five_lines) != 5: return cpu_usage_info
        if "Cpu" in top_five_lines[2]:
            cpu_line = top_five_lines[2].split(":")[-1]
            # mem_line_split = mem_line.split(",")
            for item in cpu_line.split(","):
                # print(item.split())
                item_info = item.split()
                cpu_usage_info[item_info[-1]] = float(item_info[0])
        # print(cpu_usage_info)
        return cpu_usage_info
    
    def GetMemUsage(self, top_five_lines):
        mem_usage_info = dict()
        if len(top_five_lines) != 5: return mem_usage_info
        if "Mem" in top_five_lines[3]:
            mem_line = top_five_lines[3].split(":")[-1]
            # mem_line_split = mem_line.split(",")
            for item in mem_line.split(","):
                # print(item.split())
                item_info = item.split()
                mem_usage_info[item_info[-1]] = float(item_info[0]) / 1024 / 1024
        # print(mem_usage_info)
        return mem_usage_info
    
    def GetCpuTop5(self):
        top_5 = list()
        res = self.getCmdWrite("ps aux --sort=-%cpu | head -n 6")
        top_5 = res.splitlines()
        return top_5

    def GetMemTop5(self):
        top_5 = list()
        res = self.getCmdWrite("ps aux --sort=-%mem | head -n 6")
        top_5 = res.splitlines()
        return top_5
    
    def Test(self):
        uptime = self.getStartTime()
        print("开机时间: {}".format(uptime))
        disk_info = self.getDiskInfo()
        print("磁盘信息: {}".format(disk_info))
        system_info = self.getSystemInfo()
        print("系统信息: {}".format(system_info))
        cpu_info = self.getCPUInfo()
        print("CPU信息: {}".format(cpu_info))
        load_average = self.getLoadAverage()
        print("平均负载: {}".format(load_average))
        top_five_lines = self.getTopInfo()
        print(top_five_lines)
        cpu_usage_info = self.GetCpuUsage(top_five_lines)
        print(cpu_usage_info)
        mem_usage_info = self.GetMemUsage(top_five_lines)
        print(mem_usage_info)
        cpu_top_5 = self.GetCpuTop5()
        print(cpu_top_5)
        mem_cpu_5 = self.GetMemTop5()
        print(mem_cpu_5)
    
    def WriteData(self, data):

        with open(self.__log_file, "a+") as file:
            file.write(data)
            file.write("\n")
    
    def GetNowTime(self):
        now = datetime.datetime.now()
        now_time = int(now.strftime("%s"))
        formatted_time = now.strftime("%Y-%m-%d %H:%M:%S")
        return now_time,formatted_time

    def AutoCleanByDay(self, day):
        '''自动删除day天数之前文件'''
        # 获取当前时间
        now = time.time()
        # 计算7天前的时间戳
        days_ago = now - (day * 86400)  # 7天 * 24小时 * 60分钟 * 60秒
        for filename in os.listdir(self.__save_dir):
            file_path = os.path.join(self.__save_dir, filename)
            # 确保这是一个文件（不是目录）
            if os.path.isfile(file_path):
                # 获取文件的最后修改时间
                file_mtime = os.path.getmtime(file_path)
                # 如果文件的修改时间早于7天前，删除该文件
                if file_mtime < days_ago:
                    print("Deleting:", file_path) 
                    os.remove(file_path)
    
    def Loop(self):
        self.WriteData("-----------------------------------")
        uptime = self.getStartTime()
        disk_info = self.getDiskInfo()
        system_info = self.getSystemInfo()
        cpu_info = self.getCPUInfo()
        init_data = "system: {}\nuptime: {}\ndisk: [{}/{} {}] \ncpu: (processor={} | model_name={})".format(
            system_info, uptime,
            disk_info["Used"], disk_info["Total"], disk_info["Prec"],
            cpu_info["processor"], cpu_info["model_name"]
            )
        print(init_data)
        self.WriteData(init_data)
        self.WriteData("-----------------------------------")

        while not rospy.is_shutdown():
            rospy.sleep(5)
            now_time,formatted_time = self.GetNowTime()
            try:
                # 文件自动压缩删除处理
                if os.path.exists(self.__log_file):
                    file_size = os.path.getsize(self.__log_file)
                    file_size = file_size / 1024.0 / 1024.0
                    if file_size > 1.0:
                        print(file_size)
                        # 压缩并删除文件
                        formatted_time_str = formatted_time.replace(" ", "_").replace(":", "").replace("-", "")
                        zip_file = "{}.zip".format(self.__log_file)
                        os.system("zip {} {}".format(zip_file, self.__log_file))
                        if os.path.exists(zip_file):
                            os.remove(self.__log_file)
                        # 更新文件
                        self.__log_file_idx = self.__log_file_idx + 1
                        self.__log_file = "{}_{}_{}.log".format(self.__log_origin_file, self.__log_file_idx, formatted_time_str)  

                # 自动删除15天之前数据 
                self.AutoCleanByDay(15)

                self.WriteData("\r")
                load_average = self.getLoadAverage()
                disk_info = self.getDiskInfo()
                top_five_lines = self.getTopInfo()
                cpu_usage_info = self.GetCpuUsage(top_five_lines)
                mem_usage_info = self.GetMemUsage(top_five_lines)
                cpu_used = 100 - cpu_usage_info["id"]
                mem_used = (mem_usage_info["used"] / mem_usage_info["total"]) * 100.0
                system_info = "{} | {}  load_average: {},{},{} cpu: {:.2f}%, mem: {:.2f}%, disk: [{}/{} {}]".format(now_time, formatted_time,
                    load_average["min_1"],load_average["min_5"],load_average["min_15"],
                    cpu_used, mem_used, disk_info["Used"], disk_info["Total"], disk_info["Prec"],)
                self.WriteData(system_info)


                if cpu_used > 90.0:     #cpu 进程监控
                    cpu_top_5 = self.GetCpuTop5()
                    for line in cpu_top_5:
                        self.WriteData("--> cpu_top: {}".format(line)) 
                if mem_used > 90.0:     #mem 进程监控
                    mem_cpu_5 = self.GetMemTop5()
                    for line in mem_cpu_5:
                        self.WriteData("--> mem_top: {}".format(line)) 
            except Exception as error:
                print("[Loop] error: {}".format(error))

if __name__ == "__main__":
    SystemMonitor()
    rospy.spin()
